// internal/dao/file_dao.go
package dao

import (
	"strings"

	"gorm.io/gorm"

	"github.com/jfastfiler/internal/model"
)

type FileMetadataDAO struct {
	db *gorm.DB
}

func NewFileMetadataDAO(database *Database) *FileMetadataDAO {
	return &FileMetadataDAO{db: database.db}
}

func (dao *FileMetadataDAO) Create(metadata *model.FileMetadata) error {
	return dao.db.Create(metadata).Error
}

func (dao *FileMetadataDAO) GetByID(id int) (*model.FileMetadata, error) {
	var metadata model.FileMetadata
	err := dao.db.Preload("Owner").First(&metadata, id).Error
	return &metadata, err
}

func (dao *FileMetadataDAO) GetByUUID(uuid string) (*model.FileMetadata, error) {
	var metadata model.FileMetadata
	err := dao.db.Preload("Owner").Where("uuid = ?", uuid).First(&metadata).Error
	return &metadata, err
}

func (dao *FileMetadataDAO) GetByPath(path string) (*model.FileMetadata, error) {
	var metadata model.FileMetadata
	err := dao.db.Preload("Owner").Where("path = ? AND deleted = ?", path, false).First(&metadata).Error
	return &metadata, err
}

func (dao *FileMetadataDAO) ListByParent(parentID int, params *FileQueryParams) ([]model.FileMetadata, int64, error) {
	var files []model.FileMetadata
	var total int64

	query := dao.db.Preload("Owner").Where("parent_id = ? AND deleted = ?", parentID, false)
	
	if params.Name != "" {
		query = query.Where("name LIKE ?", "%"+params.Name+"%")
	}
	if params.FileType != "" {
		switch params.FileType {
		case "image":
			query = query.Where("file_ext IN (?)", []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"})
		case "document":
			query = query.Where("file_ext IN (?)", []string{".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt"})
		case "video":
			query = query.Where("file_ext IN (?)", []string{".mp4", ".avi", ".mov", ".wmv", ".flv"})
		case "audio":
			query = query.Where("file_ext IN (?)", []string{".mp3", ".wav", ".flac", ".aac"})
		}
	}
	if params.IsDir {
		query = query.Where("is_dir = ?", true)
	}

	// 获取总数
	if err := query.Model(&model.FileMetadata{}).Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页
	offset := (params.Page - 1) * params.PageSize
	query = query.Offset(offset).Limit(params.PageSize)

	// 排序
	if params.Sort != "" {
		order := params.Sort
		if strings.ToUpper(params.Order) == "DESC" {
			order += " DESC"
		} else {
			order += " ASC"
		}
		query = query.Order(order)
	} else {
		query = query.Order("is_dir DESC, name ASC")
	}

	err := query.Find(&files).Error
	return files, total, err
}

func (dao *FileMetadataDAO) Update(metadata *model.FileMetadata) error {
	return dao.db.Save(metadata).Error
}

func (dao *FileMetadataDAO) SoftDelete(id int, userID int) error {
	return dao.db.Model(&model.FileMetadata{}).Where("id = ?", id).Updates(map[string]interface{}{
		"deleted":    true,
		"deleted_at": gorm.Expr("CURRENT_TIMESTAMP"),
		"deleted_by": userID,
	}).Error
}

func (dao *FileMetadataDAO) Move(id int, newPath string, newParentID int) error {
	return dao.db.Model(&model.FileMetadata{}).Where("id = ?", id).Updates(map[string]interface{}{
		"path":      newPath,
		"parent_id": newParentID,
		"mod_time":  gorm.Expr("CURRENT_TIMESTAMP"),
	}).Error
}

func (dao *FileMetadataDAO) Rename(id int, newName string) error {
	return dao.db.Model(&model.FileMetadata{}).Where("id = ?", id).Updates(map[string]interface{}{
		"name":     newName,
		"mod_time": gorm.Expr("CURRENT_TIMESTAMP"),
	}).Error
}

func (dao *FileMetadataDAO) UpdatePreviewStatus(id int, status int, previewPath string) error {
	updates := map[string]interface{}{
		"preview_status": status,
		"mod_time":       gorm.Expr("CURRENT_TIMESTAMP"),
	}
	if previewPath != "" {
		updates["preview_path"] = previewPath
	}
	return dao.db.Model(&model.FileMetadata{}).Where("id = ?", id).Updates(updates).Error
}

func (dao *FileMetadataDAO) GetStatistics() (*FileStatistics, error) {
	var stats FileStatistics
	
	err := dao.db.Model(&model.FileMetadata{}).Select(
		"COUNT(*) as total_files",
		"SUM(CASE WHEN is_dir = 1 THEN 1 ELSE 0 END) as total_dirs",
		"SUM(CASE WHEN is_dir = 0 THEN 1 ELSE 0 END) as total_files_count",
		"SUM(CASE WHEN is_dir = 0 THEN size ELSE 0 END) as total_size",
		"SUM(CASE WHEN deleted = 1 THEN 1 ELSE 0 END) as deleted_files",
	).Where("deleted = ?", false).Scan(&stats).Error

	if err != nil {
		return nil, err
	}

	return &stats, nil
}

func (dao *FileMetadataDAO) GetRecentFiles(userID int, limit int) ([]model.FileMetadata, error) {
	var files []model.FileMetadata
	err := dao.db.Preload("Owner").Where("owner_id = ? AND deleted = ? AND is_dir = ?", 
		userID, false, false).Order("mod_time DESC").Limit(limit).Find(&files).Error
	return files, err
}

type FileQueryParams struct {
	Name     string
	FileType string
	IsDir    bool
	Page     int
	PageSize int
	Sort     string
	Order    string
}

type FileStatistics struct {
	TotalFiles      int64 `json:"total_files"`
	TotalDirs       int64 `json:"total_dirs"`
	TotalFilesCount int64 `json:"total_files_count"`
	TotalSize       int64 `json:"total_size"`
	DeletedFiles    int64 `json:"deleted_files"`
}